import { Cartesian2 } from '../../Source/Cesium.js';
import { Resource } from '../../Source/Cesium.js';
import { DiscardMissingTileImagePolicy } from '../../Source/Cesium.js';
import pollToPromise from '../pollToPromise.js';
import { when } from '../../Source/Cesium.js';

describe('Scene/DiscardMissingTileImagePolicy', function() {

    var supportsImageBitmapOptions;
    beforeAll(function() {
        // This suite spies on requests. Resource.supportsImageBitmapOptions needs to make a request to a data URI.
        // We run it here to avoid interfering with the tests.
        return Resource.supportsImageBitmapOptions()
            .then(function(result) {
                supportsImageBitmapOptions = result;
            });
    });

    afterEach(function() {
        Resource._Implementations.createImage = Resource._DefaultImplementations.createImage;
        Resource._Implementations.loadWithXhr = Resource._DefaultImplementations.loadWithXhr;
    });

    describe('construction', function() {
        it('throws if missingImageUrl is not provided', function() {
            function constructWithoutMissingImageUrl() {
                return new DiscardMissingTileImagePolicy({
                    pixelsToCheck : [new Cartesian2(0, 0)]
                });
            }
            expect(constructWithoutMissingImageUrl).toThrowDeveloperError();
        });

        it('throws if pixelsToCheck is not provided', function() {
            function constructWithoutPixelsToCheck() {
                return new DiscardMissingTileImagePolicy({
                    missingImageUrl : 'http://some.host.invalid/missingImage.png'
                });
            }
            expect(constructWithoutPixelsToCheck).toThrowDeveloperError();
        });

        it('requests the missing image url', function() {
            var missingImageUrl = 'http://some.host.invalid/missingImage.png';

            spyOn(Resource, 'createImageBitmapFromBlob').and.callThrough();
            spyOn(Resource._Implementations, 'createImage').and.callFake(function(request, crossOrigin, deferred) {
                var url = request.url;
                if (/^blob:/.test(url)) {
                    Resource._DefaultImplementations.createImage(request, crossOrigin, deferred);
                } else {
                    expect(url).toEqual(missingImageUrl);
                    Resource._DefaultImplementations.createImage(new Request({url: 'Data/Images/Red16x16.png'}), crossOrigin, deferred);
                }
            });

            Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) {
                expect(url).toEqual(missingImageUrl);
                return Resource._DefaultImplementations.loadWithXhr('Data/Images/Red16x16.png', responseType, method, data, headers, deferred);
            };

            var policy = new DiscardMissingTileImagePolicy({
                missingImageUrl : missingImageUrl,
                pixelsToCheck : [new Cartesian2(0, 0)]
            });

            return pollToPromise(function() {
                return policy.isReady();
            }).then(function() {
                if (supportsImageBitmapOptions) {
                    expect(Resource.createImageBitmapFromBlob).toHaveBeenCalled();
                } else {
                    expect(Resource._Implementations.createImage).toHaveBeenCalled();
                }
            });
        });
    });

    describe('shouldDiscardImage', function() {
        it('discards an image that is identical to the missing image', function() {
            var promises = [];

            promises.push(Resource.fetchImage('Data/Images/Red16x16.png'));
            promises.push(Resource.fetchImage('Data/Images/Green4x4.png'));

            var missingImageUrl = 'Data/Images/Red16x16.png';
            var policy = new DiscardMissingTileImagePolicy({
                missingImageUrl : missingImageUrl,
                pixelsToCheck : [new Cartesian2(0, 0)]
            });

            promises.push(pollToPromise(function() {
                return policy.isReady();
            }));

            return when.all(promises, function(results) {
                var redImage = results[0];
                var greenImage = results[1];

                expect(policy.shouldDiscardImage(redImage)).toEqual(true);
                expect(policy.shouldDiscardImage(greenImage)).toEqual(false);
            });
        });

        it('discards an image that is identical to the missing image even if the missing image is transparent', function() {
            var promises = [];

            promises.push(Resource.fetchImage('Data/Images/Transparent.png'));

            var missingImageUrl = 'Data/Images/Transparent.png';
            var policy = new DiscardMissingTileImagePolicy({
                missingImageUrl : missingImageUrl,
                pixelsToCheck : [new Cartesian2(0, 0)]
            });

            promises.push(pollToPromise(function() {
                return policy.isReady();
            }));

            return when.all(promises, function(results) {
                var transparentImage = results[0];
                expect(policy.shouldDiscardImage(transparentImage)).toEqual(true);
            });
        });

        it('does not discard at all when the missing image is transparent and disableCheckIfAllPixelsAreTransparent is set', function() {
            var promises = [];

            promises.push(Resource.fetchImage('Data/Images/Transparent.png'));

            var missingImageUrl = 'Data/Images/Transparent.png';
            var policy = new DiscardMissingTileImagePolicy({
                missingImageUrl : missingImageUrl,
                pixelsToCheck : [new Cartesian2(0, 0)],
                disableCheckIfAllPixelsAreTransparent : true
            });

            promises.push(pollToPromise(function() {
                return policy.isReady();
            }));

            return when.all(promises, function(results) {
                var transparentImage = results[0];
                expect(policy.shouldDiscardImage(transparentImage)).toEqual(false);
            });
        });

        it('throws if called before the policy is ready', function() {
            var policy = new DiscardMissingTileImagePolicy({
                missingImageUrl : 'Data/Images/Transparent.png',
                pixelsToCheck : [new Cartesian2(0, 0)],
                disableCheckIfAllPixelsAreTransparent : true
            });

            expect(function() {
                policy.shouldDiscardImage(new Image());
            }).toThrowDeveloperError();
        });
    });
});
